/****************************************************
    [模块名]
    Add By : 陈狍子 e4ting@qq.com 2024-05-12 21:01:16
****************************************************/
package main

import (
    "archive/tar"
    "compress/gzip"
    "io"
    "net/http"
    "os"
    "time"
    "path/filepath"

    "github.com/inconshreveable/go-update"
)

type Upgrader struct {
	workpath   string
	execute    string
	PackLink   string
}

func (self *Upgrader)Init(url string) {
	self.workpath,_ = os.MkdirTemp("", "e4ting.")
	self.execute    = filepath.Join(self.workpath, filepath.Base(os.Args[0]))
	self.PackLink   = url
}

func (self *Upgrader)Cleanup() {
	// self.workpath
	logger.Println("开始清理", self.workpath)
	err := os.RemoveAll(self.workpath)
    if err != nil {
        logger.Println("清理失败", self.workpath)
    }
	return
}

func UnTarGZ(body io.Reader, _C string) error{
	// 创建一个gzip Reader
    gzr, err := gzip.NewReader(body)
    if err != nil {
        return err
    }
    defer gzr.Close()

    // 创建一个tar Reader
    tr := tar.NewReader(gzr)

    // 遍历tar中的文件
    for {
        header, err := tr.Next()
        switch {
        // 如果没有更多的文件则返回
        case err == io.EOF:
            return nil

        // 返回其他错误
        case err != nil:
            return err

        // 如果没有错误则提取文件
        case header == nil:
            continue
        }

        // 目标文件目录
        target := filepath.Join(_C, header.Name)

        // 根据tar文件中的类型执行不同的操作
        switch header.Typeflag {
        case tar.TypeDir: // 是目录
            // 创建目录
            if err := os.MkdirAll(target, 0755); err != nil {
                return err
            }
        case tar.TypeReg: // 是普通文件
            // 创建文件
            file, err := os.OpenFile(target, os.O_CREATE|os.O_RDWR, os.FileMode(header.Mode))
            if err != nil {
                return err
            }

            // 将文件写入目标路径
            if _, err := io.Copy(file, tr); err != nil {
                file.Close()
                return err
            }
            file.Close()
        }
    }
}

func (self *Upgrader)GetAndReleasePackage(url string) error {
    // 对网络地址发起http请求
    resp, err := http.Get(url)
    if err != nil {
        return err
    }
    defer resp.Body.Close()
    // 释放压缩包文件
    return UnTarGZ(resp.Body, self.workpath)
}

func (self *Upgrader) DoUpdate() {
	if err := self.GetAndReleasePackage(self.PackLink); err != nil {
		logger.Println("下载失败:", err)
		return
	}
	if !FileExists(self.execute) {
		logger.Println("包格式错误，缺失", self.execute)
		return
	}
	if !self.CoreUpdate() {
		logger.Println("核心升级失败!")
		return
	}
	self.Restart()
}

func (self *Upgrader)  CoreUpdate() bool {
	logger.Println("开始升级")
	file, err := os.Open(self.execute)
	if err != nil {
		// 处理打开文件时的错误
		logger.Println("Error opening file:", err)
		return false
	}
	defer file.Close()

	if err := update.Apply(file, update.Options{}); err != nil {
		logger.Println("升级失败")
		return false
	}
	logger.Println("升级成功")
	// node.ReportHardware()
	return true
}

func (self *Upgrader) Restart() {
	logger.Println("5s后重启")
	time.Sleep(5 * time.Second)
	os.Exit(0)
}
